using ConfigurationSettings;
using FileSystemControls.ListViewItems;
using FileSystemControls.SubForms;
using FileSystemControls.Support;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.IO;
using System.Windows.Forms;
using ZipLib;
using log4net;
using ServiceLocator;

namespace FileSystemControls
{
    /// <summary>
    /// Lists files and directories. Provides simple I/O control.
    /// </summary>
    public partial class FileSystemListView : ListView
    {
        private static readonly ILog _log = LogManager.GetLogger(typeof(FileSystemListView));
	    private IApplicationSettings _localSettings; 

        public event EventHandler<FileSystemPathChangedEventArgs> PathChanged;
        public event EventHandler<AddItemProgressEventArgs> AddItemProgress;

        #region ** Member Variables **

        private string _zipFullPathName;

        private bool _autoSort = true;

        /// <summary>
        /// The available free space for this drive.
        /// </summary>
        private long _availableFreeSpace = 0;

        private FileSystemEngine _backgroundEngine;
        private string _currentPath = String.Empty;

        private ColumnHeader _dateColumnHeader;

        /// <summary>
        /// Disposed flag.
        /// </summary>
        private bool _disposed;

        /// <summary>
        /// Right-click dragdrop context menu.
        /// </summary>
        private ContextMenuStrip _dragDropMenu;

        private string _extFilter = "*";

        /// <summary>
        /// List of dropped filenames for DragDrop operations.
        /// </summary>
        private List<string> _fileNames;

        private bool _hasFocus;
        private Rectangle _itemPopupRectangle;
        private ColumnHeader _nameColumnHeader;
        private string _nameFilter = "*";
        private FileSystemListViewItem _oldItemMouseOver;

        /// <summary>
        /// Flag to control refresh timing.
        /// </summary>
        private bool _refreshing;

        //private List<FileSystemListViewItem> _items;
        //private List<DirectoryListViewItem> _selectedDirectoryItems;
        //private List<FileListViewItem> _selectedFileItems;
        private FileInfoItemCollection<DirectoryListViewItem> _selectedDirectoryItems;
        private FileInfoItemCollection<FileListViewItem> _selectedFileItems;

        private ColumnHeader _sizeColumnHeader;

        /// <summary>
        /// Size multiplier for formatting file sizes and free space.
        /// </summary>
        private long _sizeMultiplier = 1024;

        /// <summary>
        /// Postfix for formatting file sizes and free space.
        /// </summary>
        private string _sizePostfix = " Kb";

        /// <summary>
        /// Indicates number of decimal places to display
        /// </summary>
        private int _sizePrecision = 2;

        /// <summary>
        /// Flag indicating the unit of size to use when formatting file sizes and free space.
        /// </summary>
        private SizeUnitType _sizeUnit = SizeUnitType.Kilobytes;

        /// <summary>
        /// Flag noting the column to sort on.
        /// </summary>
        private int _sortColumn;

        #region ** Context Menus **

        private ToolStripMenuItem _contextMenuClipboard;
        private ToolStripMenuItem _contextMenuCopyFullPathToClipboard;
        private ToolStripMenuItem _contextMenuCopyNameToClipboard;
        private ToolStripMenuItem _contextMenuCopyPathToClipboard;
        private ToolStripMenuItem _contextMenuItemClearSelection;
        private ToolStripMenuItem _contextMenuItemDirSpace;
        private ToolStripMenuItem _contextMenuItemDuplicate;
        private ToolStripMenuItem _contextMenuItemDuplicateDirectory;
        private ToolStripMenuItem _contextMenuItemDuplicateFile;
        private ToolStripMenuItem _contextMenuItemNothingSelected;
        private ToolStripMenuItem _contextMenuItemOpenWith;
        private ToolStripMenuItem _contextMenuItemProperties;
        private ToolStripMenuItem _contextMenuItemZip;
        private ToolStripMenuItem _contextMenuItemRename;

        private ToolStripMenuItem _contextMenuItemSelect;
        private ToolStripMenuItem _contextMenuItemSelectAll;
        private ToolStripMenuItem _contextMenuItemSelectAllDirectories;
        private ToolStripMenuItem _contextMenuItemSelectAllFiles;
        private ContextMenuStrip _contextMenuStripRightClick;

        #endregion

        private List<DirectoryListViewItem> _directories;
        private List<FileListViewItem> _files;

        /// <summary>
        /// Flag noting the state of the RightMouseButton for use in dragdrop events.
        /// </summary>
        private bool _rmbDown;

        #endregion //Member Variables

        #region ** Properties **

        public string NameFilter
        {
            get { return _nameFilter; }
            set { _nameFilter = value; }
        }

        public string ExtFilter
        {
            get { return _extFilter; }
            set { _extFilter = value; }
        }

        /// <summary>
        /// Gets the free space for the current volumn formatted acording to the Size Unit.
        /// </summary>
        [Browsable(false), ReadOnly(true)]
        public string AvailableFreeSpaceText
        {
            get
            {
                string displayFormat = "#,##0";
                if (_sizePrecision != 0)
                {
                    displayFormat += "." + new string('0', _sizePrecision);
                }

                return (_availableFreeSpace / _sizeMultiplier).ToString(displayFormat) + _sizePostfix;
            }
        }

        /// <summary>
        /// Gets or sets the Size Unit used to format file size and free space.
        /// </summary>
        public SizeUnitType SizeUnit
        {
            get { return _sizeUnit; }
            set
            {
                _sizeUnit = value;
                switch (_sizeUnit)
                {
                    case SizeUnitType.Bytes:
                        _sizeMultiplier = 1; //2^1
                        _sizePostfix = " b";
                        break;
                    case SizeUnitType.Kilobytes:
                        _sizeMultiplier = 1024; //2^10
                        _sizePostfix = " Kb";
                        break;
                    case SizeUnitType.Megabytes:
                        _sizeMultiplier = 1048576; //2^20
                        _sizePostfix = " Mb";
                        break;
                    case SizeUnitType.Gigabytes:
                        _sizeMultiplier = 1073741824; //2^30
                        _sizePostfix = " Gb";
                        break;
                }
            }
        }

        public int SizePrecision
        {
            get { return _sizePrecision; }
            set { _sizePrecision = value; }
        }

        /// <summary>
        /// Gets the current path for this FSLV.
        /// </summary>
        [Browsable(false), ReadOnly(true)]
        public string CurrentPath
        {
            get { return _currentPath; }
        }

        /// <summary>
        /// Gets a collection of selected Items in the current view.
        /// </summary>
        [Browsable(false), ReadOnly(true)]
        public new List<FileSystemListViewItem> SelectedItems
        {
            get
            {
                List<FileSystemListViewItem> tempList = new List<FileSystemListViewItem>();
                tempList.AddRange(_selectedFileItems);
                tempList.AddRange(_selectedDirectoryItems);

                return tempList;
            }
        }

        /// <summary>
        /// Gets a collection of selected Files in the current view.
        /// </summary>
        [Browsable(false), ReadOnly(true)]
        public List<FileListViewItem> SelectedFileItems
        {
            get { return _selectedFileItems; }
        }

        public List<FileListViewItem> Files
        {
            get { return _files; }
        }

        /// <summary>
        /// Gets a collection of selected directories in the current view.
        /// </summary>
        [Browsable(false), ReadOnly(true)]
        public List<DirectoryListViewItem> SelectedDirectoryItems
        {
            get { return _selectedDirectoryItems; }
        }

        public List<DirectoryListViewItem> Directories
        {
            get { return _directories; }
        }

        /// <summary>
        /// Gets or sets a value indicating whether this FSLV will sort items automatically.
        /// </summary>
        public bool AutoSort
        {
            get { return _autoSort; }

            set { _autoSort = value; }
        }

        /// <summary>
        /// Gets or sets the column to sort on.
        /// </summary>
        public Column SortColumn
        {
            get { return (Column)_sortColumn; }

            set { _sortColumn = (int)value; }
        }

        #endregion //Public Properties

        #region ** Constructors / Destructors **

        /// <summary>
        /// Initializes a new FileSystemListView object
        /// </summary>
        public FileSystemListView()
        {
            using (ThreadContext.Stacks["NDC"].Push("FileSystemListView.ctor"))
            {
				 _localSettings = Locator.Resolve<IApplicationSettings>();

                _log.DebugFormat("Clear the ListView columns.");
                Columns.Clear();

                _log.DebugFormat("Instatiate the background engine.");
                _backgroundEngine = new FileSystemEngine();
                _log.DebugFormat("Attach the event handlers.");
                _backgroundEngine.AddItemProgress += _backgroundEngine_AddItemProgress;
                _backgroundEngine.AddItemComplete += _backgroundEngine_AddItemComplete;

                _log.DebugFormat("Call SetLocalVariables.");
                SetLocalVariables();

                _log.DebugFormat("Call SetupColumns.");
                SetupColumns();

                _log.DebugFormat("Call CreateDragDropMenu.");
                CreateDragDropMenu();

                _log.DebugFormat("Call CreateRightClickMenu");
                CreateRightClickMenu();

                /*****************************************************************************/

                ListViewItemSorter = new FileSystemListViewItemComparer(_sortColumn, Sorting);

                _log.DebugFormat("Initialize brushes.");
                InitializeBrushes();
                //TODO:I left off here. Add logs from here down
            }
        }

        /// <summary>
        /// Set local default settings.
        /// </summary>
        private void SetLocalVariables()
        {
            _hasFocus = false;
            OwnerDraw = true;
            CheckBoxes = false;

            //_plainFileFont = new Font("Courier New", 9.75F, FontStyle.Regular);
            //_columnFont = new Font("Courier New", 9.75F, FontStyle.Regular);

            Font = new Font("Courier New", 9.75F, FontStyle.Regular, GraphicsUnit.Point, ((0)));

            AllowColumnReorder = false;
            AllowDrop = true;
            DoubleBuffered = true;
            View = View.Details;
            FullRowSelect = true;
            BorderStyle = BorderStyle.None;
            ShowGroups = false;
            HotTracking = false;
            ShowItemToolTips = false; //true
            HoverSelection = false;

            SetStyle(ControlStyles.AllPaintingInWmPaint, false);
            SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
            SetStyle(ControlStyles.ResizeRedraw, true);
            SetStyle(ControlStyles.Selectable, true);
            SetStyle(ControlStyles.UserMouse, true);
            SetStyle(ControlStyles.UserPaint, false);

            _sortColumn = 0;
            Sorting = SortOrder.Ascending;

            _files = new List<FileListViewItem>();
            _directories = new List<DirectoryListViewItem>();

            _selectedFileItems = new FileInfoItemCollection<FileListViewItem>();
            _selectedDirectoryItems = new FileInfoItemCollection<DirectoryListViewItem>();

            _fileNames = new List<string>();
            //_items = new List<FileSystemListViewItem>();

        }

        private void SetupColumns()
        {
            _nameColumnHeader = new ColumnHeader
                {
                    Text = @"Name",
                    Width = 190,
                    TextAlign = HorizontalAlignment.Left
                };

            _sizeColumnHeader = new ColumnHeader
                {
                    Text = @"Size",
                    Width = 90,
                    TextAlign = HorizontalAlignment.Left
                };

            _dateColumnHeader = new ColumnHeader
                {
                    Text = @"Date",
                    Width = 190,
                    TextAlign = HorizontalAlignment.Right
                };

            Columns.Add(_nameColumnHeader);
            Columns.Add(_sizeColumnHeader);
            Columns.Add(_dateColumnHeader);

            //NameColumnHeader.Dispose();
            //SizeColumnHeader.Dispose();
            //DateColumnHeader.Dispose();
        }

        private void CreateDragDropMenu()
        {
            ToolStripMenuItem copyHere = null;
            ToolStripMenuItem moveHere = null;
            ToolStripMenuItem rmbCancel = null;
            ToolStripSeparator toolstripSeperator = null;

            #region ** DragDrop Menu **

            try
            {
                copyHere = new ToolStripMenuItem("Copy Here", null, OnRMBCopyHere);
                moveHere = new ToolStripMenuItem("Move Here", null, OnRMBMoveHere);
                rmbCancel = new ToolStripMenuItem("Cancel", null, OnRMBCancel);
                toolstripSeperator = new ToolStripSeparator();

                _dragDropMenu = new ContextMenuStrip();
                _dragDropMenu.Items.AddRange(
                    new ToolStripItem[]
                        {
                            copyHere, moveHere,
                            toolstripSeperator, rmbCancel
                        });
            }
            finally
            {
                if (copyHere != null)
                {
                    copyHere.Dispose();
                }
                if (moveHere != null)
                {
                    moveHere.Dispose();
                }
                if (rmbCancel != null)
                {
                    rmbCancel.Dispose();
                }
                if (toolstripSeperator != null)
                {
                    toolstripSeperator.Dispose();
                }
            }

            #endregion
        }

        private void CreateRightClickMenu()
        {
            #region ** Right Click Menu **

            _contextMenuItemOpenWith = new ToolStripMenuItem
                {
                    Size = new Size(215, 22),
                    Text = @"Open With...",
                    Visible = false
                };

            /***************************************************************************************/
            /** Duplicate Items **/
            _contextMenuItemDuplicateFile = new ToolStripMenuItem
                {
                    Size = new Size(215, 22),
                    Text = @"Duplicate File"
                };
            _contextMenuItemDuplicateFile.Click += contextMenuItemDuplicateFile_Click;

            _contextMenuItemDuplicateDirectory = new ToolStripMenuItem
                {
                    Size = new Size(215, 22),
                    Text = @"Duplicate Directory"
                };
            _contextMenuItemDuplicateDirectory.Click += contextMenuItemDuplicateDirectory_Click;

            _contextMenuItemDuplicate = new ToolStripMenuItem
                {
                    Size = new Size(215, 22),
                    Text = @"Duplicate..."
                };
            _contextMenuItemDuplicate.DropDownItems.AddRange(new ToolStripItem[]
                {
                    _contextMenuItemDuplicateFile
                    , _contextMenuItemDuplicateDirectory
                });
            /***************************************************************************************/

            _contextMenuItemDirSpace = new ToolStripMenuItem
                {
                    Size = new Size(215, 22),
                    Text = @"DirSpace",
                    Visible = false
                };
            _contextMenuItemDirSpace.Click += contextMenuItemDirSpace_Click;

            _contextMenuItemRename = new ToolStripMenuItem
                {
                    Size = new Size(215, 22),

                    Text = @"Rename",
                    Visible = false
                };
            _contextMenuItemRename.Click += contextMenuItemRename_Click;

            _contextMenuItemNothingSelected = new ToolStripMenuItem
                {
                    Enabled = false,
                    Size = new Size(215, 22),
                    Text = @"Nothing Selected",
                    Visible = false
                };

            /***************************************************************************************/
            /** Clipboard Items **/
            _contextMenuCopyNameToClipboard = new ToolStripMenuItem
                {
                    Size = new Size(215, 22),
                    Text = @"Copy Name to Clipboard"
                };
            _contextMenuCopyNameToClipboard.Click += contextMenuCopyNameToClipboard_Click;

            _contextMenuCopyPathToClipboard = new ToolStripMenuItem
                {
                    Size = new Size(215, 22),
                    Text = @"Copy Path to Clipboard"
                };
            _contextMenuCopyPathToClipboard.Click += contextMenuCopyPathToClipboard_Click;

            _contextMenuCopyFullPathToClipboard = new ToolStripMenuItem
                {
                    Size = new Size(215, 22),
                    Text = @"Copy Full Path to Clipboard"
                };
            _contextMenuCopyFullPathToClipboard.Click += contextMenuCopyFullPathToClipboard_Click;

            _contextMenuClipboard = new ToolStripMenuItem
                {
                    Size = new Size(215, 22),
                    Text = @"Clipboard..."
                };
            _contextMenuClipboard.DropDownItems.AddRange(new ToolStripItem[]
                {
                    _contextMenuCopyNameToClipboard
                    , _contextMenuCopyPathToClipboard
                    , _contextMenuCopyFullPathToClipboard
                });
            /*****************************************************************************************/
            /*************************************************************************************/
            /** Select Items **/
            _contextMenuItemSelectAll = new ToolStripMenuItem
                {
                    Size = new Size(215, 22),
                    Text = @"Select All"
                };
            _contextMenuItemSelectAll.Click += contextMenuItemSelectAll_Click;

            _contextMenuItemSelectAllFiles = new ToolStripMenuItem
                {
                    Size = new Size(215, 22),
                    Text = @"Select All Files"
                };
            _contextMenuItemSelectAllFiles.Click += contextMenuItemSelectAllFiles_Click;

            _contextMenuItemSelectAllDirectories = new ToolStripMenuItem
                {
                    Size = new Size(215, 22),
                    Text = @"Select All Directories"
                };
            _contextMenuItemSelectAllDirectories.Click += contextMenuItemSelectAllDirectories_Click;

            _contextMenuItemClearSelection = new ToolStripMenuItem
                {
                    Size = new Size(215, 22),
                    Text = @"Clear Selection",
                    Visible = false
                };
            _contextMenuItemClearSelection.Click += contextMenuItemClearSelection_Click;

            _contextMenuItemSelect = new ToolStripMenuItem
                {
                    Size = new Size(215, 22),
                    Text = @"Selection...",
                    Visible = true
                };
            _contextMenuItemSelect.DropDownItems.AddRange(new ToolStripItem[]
                {
                    _contextMenuItemSelectAll
                    , _contextMenuItemSelectAllFiles
                    , _contextMenuItemSelectAllDirectories
                    , _contextMenuItemClearSelection
                });
            /********************************************************************************************/

            _contextMenuItemProperties = new ToolStripMenuItem
                {
                    Size = new Size(215, 22),
                    Text = @"Properties"
                };
            _contextMenuItemProperties.Click += contextMenuItemProperties_Click;
            /**********************************************************************************************/
            _contextMenuItemZip = new ToolStripMenuItem
            {
                Size = new Size(215, 22),
                Text = @"Zip"
            };
            _contextMenuItemZip.Click += contextMenuItemZip_Click;

            _contextMenuStripRightClick = new ContextMenuStrip();

            // 
            // contextMenuStripRightClick
            // 
            _contextMenuStripRightClick.Items.AddRange(new ToolStripItem[]
                {
                    _contextMenuItemOpenWith
                    , _contextMenuItemDuplicate
                    , _contextMenuItemDirSpace
                    , _contextMenuItemRename
                    , _contextMenuItemNothingSelected
                    , _contextMenuClipboard
                    , _contextMenuItemSelect
                    , _contextMenuItemProperties
                    ,_contextMenuItemZip
                });

            _contextMenuStripRightClick.Name = "RightClickMenuStrip";
            _contextMenuStripRightClick.Size = new Size(216, 312);
            _contextMenuStripRightClick.Opening += contextMenuStripRightClick_Opening;

            ContextMenuStrip = _contextMenuStripRightClick;

            #endregion
        }
        
        private void InitializeBrushes()
        {
            //Build Initial Brush
            _plainColumnPaintBrushes = new List<LinearGradientBrush>();
            _plainColumnPaintBrushes.Insert(0, null);
            _plainColumnPaintBrushes.Insert(1, null);
            _plainColumnPaintBrushes.Insert(2, null);

            _highlightColumnPaintBrushes = new List<LinearGradientBrush>();
            _highlightColumnPaintBrushes.Insert(0, null);
            _highlightColumnPaintBrushes.Insert(1, null);
            _highlightColumnPaintBrushes.Insert(2, null);

            _plainFilePaintBrushes = new List<LinearGradientBrush>();
            _plainFilePaintBrushes.Insert(0, null);
            _plainFilePaintBrushes.Insert(1, null);
            _plainFilePaintBrushes.Insert(2, null);

            _selectedFilePaintBrushes = new List<LinearGradientBrush>();
            _selectedFilePaintBrushes.Insert(0, null);
            _selectedFilePaintBrushes.Insert(1, null);
            _selectedFilePaintBrushes.Insert(2, null);

            _mouseOverFilePaintBrushes = new List<LinearGradientBrush>();
            _mouseOverFilePaintBrushes.Insert(0, null);
            _mouseOverFilePaintBrushes.Insert(1, null);
            _mouseOverFilePaintBrushes.Insert(2, null);

            _selectedMouseOverFilePaintBrushes = new List<LinearGradientBrush>();
            _selectedMouseOverFilePaintBrushes.Insert(0, null);
            _selectedMouseOverFilePaintBrushes.Insert(1, null);
            _selectedMouseOverFilePaintBrushes.Insert(2, null);

            _plainDirectoryPaintBrushes = new List<LinearGradientBrush>();
            _plainDirectoryPaintBrushes.Insert(0, null);
            _plainDirectoryPaintBrushes.Insert(1, null);
            _plainDirectoryPaintBrushes.Insert(2, null);

            _selectedDirectoryPaintBrushes = new List<LinearGradientBrush>();
            _selectedDirectoryPaintBrushes.Insert(0, null);
            _selectedDirectoryPaintBrushes.Insert(1, null);
            _selectedDirectoryPaintBrushes.Insert(2, null);

            _mouseOverDirectoryPaintBrushes = new List<LinearGradientBrush>();
            _mouseOverDirectoryPaintBrushes.Insert(0, null);
            _mouseOverDirectoryPaintBrushes.Insert(1, null);
            _mouseOverDirectoryPaintBrushes.Insert(2, null);

            _selectedMouseOverDirectoryPaintBrushes = new List<LinearGradientBrush>();
            _selectedMouseOverDirectoryPaintBrushes.Insert(0, null);
            _selectedMouseOverDirectoryPaintBrushes.Insert(1, null);
            _selectedMouseOverDirectoryPaintBrushes.Insert(2, null);
        }
        
        //Use this as an example of how to implement Dispose.
        //If you have objects that need to be FinalizeDisposed you can do that from the Dispose() method
        //If the Finalizer is the one calling dispose then you can't touch Managed resources so skip those.
        /// <summary>
        /// Dispose of managed resources properly.
        /// </summary>
        //public void Dispose()
        //{
        //    Dispose(true);
        //    GC.SuppressFinalize(this);
        //}
        protected override void Dispose(bool argCodeDisposing)
        {
            if (!_disposed)
            {
                if (argCodeDisposing)
                {

                    if (_backgroundEngine != null)
                    {
                        _backgroundEngine.AddItemProgress -= _backgroundEngine_AddItemProgress;
                        //_backgroundEngine.Dispose();
                    }

                    FreeFileBrushes();
                    FreeDirectoryBrushes();
                    FreeColumnBrushes();
                    FreeFonts();

                    if (_dragDropMenu != null)
                    {
                        _dragDropMenu.Dispose();
                    }
                }

                _disposed = true;
                base.Dispose(argCodeDisposing);
            }
        }

        private void FreeFonts()
        {
            //if (_plainFileFont != null)
            //    _plainFileFont.Dispose();
            //if (_selectedFileFont != null)
            //    _selectedFileFont.Dispose();
            //if (_mouseOverFileFont != null)
            //    _mouseOverFileFont.Dispose();
            //if (_selectedMouseOverFileFont != null)
            //    _selectedMouseOverFileFont.Dispose();

            //if (_plainDirectoryFont != null)
            //    _plainDirectoryFont.Dispose();
            //if (_selectedDirectoryFont != null)
            //    _selectedDirectoryFont.Dispose();
            //if (_mouseOverDirectoryFont != null)
            //    _mouseOverDirectoryFont.Dispose();
            //if (_selectedMouseOverDirectoryFont != null)
            //    _selectedMouseOverDirectoryFont.Dispose();

            //if (_columnFont != null)
            //    _columnFont.Dispose();

        }

        private void FreeColumnBrushes()
        {

            #region ** Column Brushes **
            //Check for use. Vaild.
            if (_nameColumnHeader != null)
            {
                _nameColumnHeader.Dispose();
            }
            if (_sizeColumnHeader != null)
            {
                _sizeColumnHeader.Dispose();
            }
            if (_dateColumnHeader != null)
            {
                _dateColumnHeader.Dispose();
            }
            #endregion

            #region ** Column Brushes [0] **
            //Checked for use. Valid.
            if (_plainColumnPaintBrushes[0] != null)
            {
                _plainColumnPaintBrushes[0].Dispose();
            }
            if (_highlightColumnPaintBrushes[0] != null)
            {
                _highlightColumnPaintBrushes[0].Dispose();
            }
            #endregion

            #region ** Column Brushes [1] **
            //Checked for use. Valid.
            if (_plainColumnPaintBrushes[1] != null)
            {
                _plainColumnPaintBrushes[1].Dispose();
            }
            if (_highlightColumnPaintBrushes[1] != null)
            {
                _highlightColumnPaintBrushes[1].Dispose();
            }
            #endregion

            #region ** Column Brushes [2] **
            //Checked for use. Valid.
            if (_plainColumnPaintBrushes[2] != null)
            {
                _plainColumnPaintBrushes[2].Dispose();
            }
            if (_highlightColumnPaintBrushes[2] != null)
            {
                _highlightColumnPaintBrushes[2].Dispose();
            }
            #endregion

        }

        private void FreeDirectoryBrushes()
        {
            #region ** Directory Brushes **
            //Checked for use. Valid.
            if (_plainDirectoryFontBrush != null)
            {
                _plainDirectoryFontBrush.Dispose();
            }
            if (_selectedDirectoryFontBrush != null)
            {
                _selectedDirectoryFontBrush.Dispose();
            }
            if (_mouseOverDirectoryFontBrush != null)
            {
                _mouseOverDirectoryFontBrush.Dispose();
            }
            if (_selectedMouseOverDirectoryFontBrush != null)
            {
                _selectedMouseOverDirectoryFontBrush.Dispose();
            }
            #endregion

            #region ** Directory Brushes [0] **
            //Checked for use. Valid.
            if (_plainDirectoryPaintBrushes[0] != null)
            {
                _plainDirectoryPaintBrushes[0].Dispose();
            }
            if (_selectedDirectoryPaintBrushes[0] != null)
            {
                _selectedDirectoryPaintBrushes[0].Dispose();
            }
            if (_mouseOverDirectoryPaintBrushes[0] != null)
            {
                _mouseOverDirectoryPaintBrushes[0].Dispose();
            }
            if (_selectedMouseOverDirectoryPaintBrushes[0] != null)
            {
                _selectedMouseOverDirectoryPaintBrushes[0].Dispose();
            }
            #endregion

            #region ** Directory Brushes [1] **
            //Checked for use. Valid.
            if (_plainDirectoryPaintBrushes[1] != null)
            {
                _plainDirectoryPaintBrushes[1].Dispose();
            }
            if (_selectedDirectoryPaintBrushes[1] != null)
            {
                _selectedDirectoryPaintBrushes[1].Dispose();
            }
            if (_mouseOverDirectoryPaintBrushes[1] != null)
            {
                _mouseOverDirectoryPaintBrushes[1].Dispose();
            }
            if (_selectedMouseOverDirectoryPaintBrushes[1] != null)
            {
                _selectedMouseOverDirectoryPaintBrushes[1].Dispose();
            }
            #endregion

            #region ** Plain Directory Brushes [2] **
            //Checked for use. Valid.
            if (_plainDirectoryPaintBrushes[2] != null)
            {
                _plainDirectoryPaintBrushes[2].Dispose();
            }
            if (_selectedDirectoryPaintBrushes[2] != null)
            {
                _selectedDirectoryPaintBrushes[2].Dispose();
            }
            if (_mouseOverDirectoryPaintBrushes[2] != null)
            {
                _mouseOverDirectoryPaintBrushes[2].Dispose();
            }
            if (_selectedMouseOverDirectoryPaintBrushes[2] != null)
            {
                _selectedMouseOverDirectoryPaintBrushes[2].Dispose();
            }
            #endregion

        }

        private void FreeFileBrushes()
        {
            #region ** File Brushes **
            //Checked for use. Valid.
            if (_plainFileFontBrush != null)
            {
                _plainFileFontBrush.Dispose();
            }
            if (_selectedFileFontBrush != null)
            {
                _selectedFileFontBrush.Dispose();
            }
            if (_mouseOverFileFontBrush != null)
            {
                _mouseOverFileFontBrush.Dispose();
            }
            if (_selectedMouseOverFileFontBrush != null)
            {
                _selectedMouseOverFileFontBrush.Dispose();
            }
            #endregion

            #region ** File Brushes [0] **
            //Checked for use. Valid.
            //TODO: Change this to a foreach so I don't have so much code
            if (_plainFilePaintBrushes[0] != null)
            {
                _plainFilePaintBrushes[0].Dispose();
            }
            if (_selectedFilePaintBrushes[0] != null)
            {
                _selectedFilePaintBrushes[0].Dispose();
            }
            if (_mouseOverFilePaintBrushes[0] != null)
            {
                _mouseOverFilePaintBrushes[0].Dispose();
            }
            if (_selectedMouseOverFilePaintBrushes[0] != null)
            {
                _selectedMouseOverFilePaintBrushes[0].Dispose();
            }
            #endregion

            #region ** File Brushes [1] **
            //Checked for use. Valid.
            if (_plainFilePaintBrushes[1] != null)
            {
                _plainFilePaintBrushes[1].Dispose();
            }
            if (_selectedFilePaintBrushes[1] != null)
            {
                _selectedFilePaintBrushes[1].Dispose();
            }
            if (_mouseOverFilePaintBrushes[1] != null)
            {
                _mouseOverFilePaintBrushes[1].Dispose();
            }
            if (_selectedMouseOverFilePaintBrushes[1] != null)
            {
                _selectedMouseOverFilePaintBrushes[1].Dispose();
            }
            #endregion

            #region ** File Brushes [2] **
            //Checked for use. Valid.
            if (_plainFilePaintBrushes[2] != null)
            {
                _plainFilePaintBrushes[2].Dispose();
            }
            if (_selectedFilePaintBrushes[2] != null)
            {
                _selectedFilePaintBrushes[2].Dispose();
            }
            if (_mouseOverFilePaintBrushes[2] != null)
            {
                _mouseOverFilePaintBrushes[2].Dispose();
            }
            if (_selectedMouseOverFilePaintBrushes[2] != null)
            {
                _selectedMouseOverFilePaintBrushes[2].Dispose();
            }
            #endregion
        }

        #endregion

        #region ** Public Methods **

        /// <summary>
        /// Reads the configuration file and sets any elements that can be configured.
        /// </summary>
        public void SetConfiguration()
        {
            //TODO: 024 - Optimize the loading of configuration values

			SizeUnit = _localSettings.SizeUnit;
			_sizePrecision = _localSettings.SizePrecision;

            #region ** Set FileTrackerConfiguration **

			BackColor = _localSettings.ListViewBackColor;

			FocusColor = _localSettings.FocusColor;

			_fileSettings = _localSettings.FileSettings;

			_directorySettings = _localSettings.DirectorySettings;

            #region ** Column Colors  **

			_columnSettings = _localSettings.ColumnSettings;

            //_plainColumnNameColor1 = ConfigSettings.ColumnSettings.PlainSettings.NameColors.Color1;// PlainColumnNameColor1;
            //_plainColumnNameColor2 = ConfigSettings.ColumnSettings.PlainSettings.NameColors.Color2;// PlainColumnNameColor2;
            //_plainColumnNameColorDirection = ConfigSettings.ColumnSettings.PlainSettings.NameColors.Direction;// PlainColumnNameColorDirection;

            //_plainColumnSizeColor1 = ConfigSettings.ColumnSettings.PlainSettings.SizeColors.Color1;// PlainColumnSizeColor1;
            //_plainColumnSizeColor2 = ConfigSettings.ColumnSettings.PlainSettings.SizeColors.Color2;// PlainColumnSizeColor2;
            //_plainColumnSizeColorDirection = ConfigSettings.ColumnSettings.PlainSettings.SizeColors.Direction;// PlainColumnSizeColorDirection;

            //_plainColumnDateColor1 = ConfigSettings.ColumnSettings.PlainSettings.DateColors.Color1;// PlainColumnDateColor1;
            //_plainColumnDateColor2 = ConfigSettings.ColumnSettings.PlainSettings.DateColors.Color2;// PlainColumnDateColor2;
            //_plainColumnDateColorDirection = ConfigSettings.ColumnSettings.PlainSettings.DateColors.Direction;// PlainColumnDateColorDirection;

            #endregion

            #region ** Coloumn highlight Colors **

            //_highlightColumnNameColor1 = ConfigSettings.ColumnSettings.HighlightSettings.NameColors.Color1;// HighlightColumnNameColor1;
            //_highlightColumnNameColor2 = ConfigSettings.ColumnSettings.HighlightSettings.NameColors.Color2;// HighlightColumnNameColor2;
            //_highlightColumnNameColorDirection = ConfigSettings.ColumnSettings.HighlightSettings.NameColors.Direction;// HighlightColumnNameColorDirection;

            //_highlightColumnSizeColor1 = ConfigSettings.ColumnSettings.HighlightSettings.SizeColors.Color1;// HighlightColumnSizeColor1;
            //_highlightColumnSizeColor2 = ConfigSettings.ColumnSettings.HighlightSettings.SizeColors.Color2;// HighlightColumnSizeColor2;
            //_highlightColumnSizeColorDirection = ConfigSettings.ColumnSettings.HighlightSettings.SizeColors.Direction;// HighlightColumnSizeColorDirection;

            //_highlightColumnDateColor1 = ConfigSettings.ColumnSettings.HighlightSettings.DateColors.Color1;// HighlightColumnDateColor1;
            //_highlightColumnDateColor2 = ConfigSettings.ColumnSettings.HighlightSettings.DateColors.Color2;// HighlightColumnDateColor2;
            //_highlightColumnDateColorDirection = ConfigSettings.ColumnSettings.HighlightSettings.DateColors.Direction;// HighlightColumnDateColorDirection;

            #endregion

            #region ** Fonts **

            //_plainFileFont = ConfigSettings.FileSettings.PlainSettings.Font;// PlainFileFont;
            //_plainFileForeColor = ConfigSettings.FileSettings.PlainSettings.FontColor;// PlainFileForeColor;
            //_selectedFileFont = ConfigSettings.FileSettings.SelectedSettings.Font;// SelectedFileFont;
            //_selectedFileForeColor = ConfigSettings.FileSettings.SelectedSettings.FontColor;// SelectedFileForeColor;
            //_mouseOverFileFont = ConfigSettings.FileSettings.MouseOverSettings.Font;// MouseOverFileFont;
            //_mouseOverFileForeColor = ConfigSettings.FileSettings.MouseOverSettings.FontColor;// MouseOverFileForeColor;
            //_selectedMouseOverFileFont = ConfigSettings.FileSettings.SelectedMouseOverSettings.Font;// SelectedMouseOverFileFont;
            //_selectedMouseOverFileForeColor = ConfigSettings.FileSettings.SelectedMouseOverSettings.FontColor;// SelectedMouseOverFileForeColor;

            //_plainDirectoryFont = ConfigSettings.DirectorySettings.PlainSettings.Font;// PlainDirectoryFont;
            //_plainDirectoryForeColor = ConfigSettings.DirectorySettings.PlainSettings.FontColor;// PlainDirectoryForeColor;
            //_selectedDirectoryFont = ConfigSettings.DirectorySettings.SelectedSettings.Font;// SelectedDirectoryFont;
            //_selectedDirectoryForeColor = ConfigSettings.DirectorySettings.SelectedSettings.FontColor;// SelectedDirectoryForeColor;
            //_mouseOverDirectoryFont = ConfigSettings.DirectorySettings.MouseOverSettings.Font;// MouseOverDirectoryFont;
            //_mouseOverDirectoryForeColor = ConfigSettings.DirectorySettings.MouseOverSettings.FontColor;// MouseOverDirectoryForeColor;
            //_selectedMouseOverDirectoryFont = ConfigSettings.DirectorySettings.SelectedMouseOverSettings.Font;// SelectedMouseOverDirectoryFont;
            //_selectedMouseOverDirectoryForeColor = ConfigSettings.DirectorySettings.SelectedMouseOverSettings.FontColor;// SelectedMouseOverDirectoryForeColor;

            //_columnFont = ConfigSettings.ColumnSettings.PlainSettings.Font;// PlainColumnFont;
            //_columnForeColor = ConfigSettings.ColumnSettings.PlainSettings.FontColor;// PlainColumnForeColor;

            #endregion

			_autoSort = _localSettings.LeftAutoSort;
			SortColumn = _localSettings.LeftDefaultSortColumn;

            #endregion

            _plainColumnPaintBrushes[0] = null;
            _plainColumnPaintBrushes[1] = null;
            _plainColumnPaintBrushes[2] = null;

            _highlightColumnPaintBrushes[0] = null;
            _highlightColumnPaintBrushes[1] = null;
            _highlightColumnPaintBrushes[2] = null;

            _plainFilePaintBrushes[0] = null;
            _plainFilePaintBrushes[1] = null;
            _plainFilePaintBrushes[2] = null;

            _selectedFilePaintBrushes[0] = null;
            _selectedFilePaintBrushes[1] = null;
            _selectedFilePaintBrushes[2] = null;

            _mouseOverFilePaintBrushes[0] = null;
            _mouseOverFilePaintBrushes[1] = null;
            _mouseOverFilePaintBrushes[2] = null;

            _selectedMouseOverFilePaintBrushes[0] = null;
            _selectedMouseOverFilePaintBrushes[1] = null;
            _selectedMouseOverFilePaintBrushes[2] = null;

            _plainDirectoryPaintBrushes[0] = null;
            _plainDirectoryPaintBrushes[1] = null;
            _plainDirectoryPaintBrushes[2] = null;

            _selectedDirectoryPaintBrushes[0] = null;
            _selectedDirectoryPaintBrushes[1] = null;
            _selectedDirectoryPaintBrushes[2] = null;

            _mouseOverDirectoryPaintBrushes[0] = null;
            _mouseOverDirectoryPaintBrushes[1] = null;
            _mouseOverDirectoryPaintBrushes[2] = null;

            _selectedMouseOverDirectoryPaintBrushes[0] = null;
            _selectedMouseOverDirectoryPaintBrushes[1] = null;
            _selectedMouseOverDirectoryPaintBrushes[2] = null;

            LoadOpenWith();
            Invalidate(true);
        }

        /// <summary>
        /// Scans the configuration object and adds "Open With" entries to the context menu.
        /// </summary>
        //public void LoadOpenWith(ApplicationSettings ConfigSettings)
        public void LoadOpenWith()
        {
            try
            {
                _contextMenuItemOpenWith.DropDownItems.Clear();

				foreach (KeyValuePair<string, string> programEntry in _localSettings.ProgramList)
                {
	                string programName = programEntry.Key;
	                string programAction = programEntry.Value;

	                ToolStripMenuItem openWithItem = new ToolStripMenuItem(programName);
	                openWithItem.Click += OpenWith_Click;

	                openWithItem.Tag = programAction;

	                _contextMenuItemOpenWith.DropDownItems.Add(openWithItem);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(@"Error in LoadOpenWith: " + ex.Message);
            }
        }

        /// <summary>
        /// Sends the selected FileList to the selected "Open With" program.
        /// </summary>
        /// <param name="argSender">The ToolStripMenuItem object that raised this event.</param>
        /// <param name="argEventArgs">The event arguments object. Unused.</param>
        private void OpenWith_Click(object argSender, EventArgs argEventArgs)
        {
            try
            {
                ToolStripMenuItem openWithItem = (ToolStripMenuItem)argSender;

                foreach (FileSystemListViewItem currentItem in SelectedItems)
                {
                    Process.Start(openWithItem.Tag.ToString(), " \"" + currentItem.FullPath + "\" ");
                }

                ClearSelection();
            }
            catch (Exception ex)
            {
                MessageBox.Show(@"Error in OpenWith_Click" + ex.Message);
            }
        }

        /// <summary>
        /// Duplicate file into the same directory.
        /// </summary>
        /// <param name="argSender">Unused</param>
        /// <param name="argEventArgs">Unused</param>
        private void contextMenuItemDuplicateFile_Click(object argSender, EventArgs argEventArgs)
        {
            foreach (FileListViewItem currentItem in _selectedFileItems)
            {
                currentItem.Duplicate();
            }
        }

        /// <summary>
        /// Duplicate a subdirectory into the same directory.
        /// </summary>
        /// <param name="argSender">Unused</param>
        /// <param name="argEventArgs">Unused</param>
        private void contextMenuItemDuplicateDirectory_Click(object argSender, EventArgs argEventArgs)
        {
            List<DirectoryListViewItem> dirList = _selectedDirectoryItems;
            foreach (DirectoryListViewItem currentItem in dirList)
            {
                currentItem.Duplicate();
            }
        }

        /// <summary>
        /// Gets the combined size of all files under this directory.
        /// </summary>
        /// <param name="argSender">Unused</param>
        /// <param name="argEventArgs">Unused</param>
        private void contextMenuItemDirSpace_Click(object argSender, EventArgs argEventArgs)
        {
            try
            {
                Cursor.Current = Cursors.WaitCursor;

                //Get the directory to parse
                foreach (DirectoryListViewItem currentDirectory in _selectedDirectoryItems)
                {
                    currentDirectory.GetDirSizeAsync();
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(@"Error in toolStripMenuItemDirSpace_Click" + ex.Message);
            }
            finally
            {
                Cursor.Current = Cursors.Default;
            }
        }

        /// <summary>
        /// Stubs out RenameItem method.
        /// </summary>
        /// <param name="argSender">Unused</param>
        /// <param name="argEventArgs">Unused</param>
        private void contextMenuItemRename_Click(object argSender, EventArgs argEventArgs)
        {
            //This allows me to use the FileTrackerConfiguration.KeyMethod delegate
            //  for all the method calls rather than being forced to pass
            //  not needed arguments.
            RenameItems();
        }

        private void contextMenuCopyNameToClipboard_Click(object argSender, EventArgs argEventArgs)
        {
            string clipboardText = String.Empty;

            Clipboard.Clear();
            foreach (FileSystemListViewItem currentItem in SelectedItems)
            {
                clipboardText += currentItem.Name + "\r\n";
            }

            Clipboard.SetText(clipboardText, TextDataFormat.Text);
        }

        private void contextMenuCopyPathToClipboard_Click(object argSender, EventArgs argEventArgs)
        {
            string clipboardText = String.Empty;

            Clipboard.Clear();
            foreach (FileSystemListViewItem currentItem in SelectedItems)
            {
                clipboardText += currentItem.Path + "\r\n";
            }

            Clipboard.SetText(clipboardText, TextDataFormat.Text);
        }

        //TODO: Move all these to public methods so they can be used from the outside
        private void contextMenuCopyFullPathToClipboard_Click(object argSender, EventArgs argEventArgs)
        {
            string clipboardText = String.Empty;

            Clipboard.Clear();
            foreach (FileSystemListViewItem currentItem in SelectedItems)
            {
                clipboardText += currentItem.FullPath + "\r\n";
            }

            Clipboard.SetText(clipboardText, TextDataFormat.Text);
        }

        /// <summary>
        /// Select all the items in a directory.
        /// </summary>
        /// <param name="argSender">Unused</param>
        /// <param name="argEventArgs">Unused</param>
        private void contextMenuItemSelectAll_Click(object argSender, EventArgs argEventArgs)
        {
            SelectAllItems();
        }

        /// <summary>
        /// Select all the files in this directory.
        /// </summary>
        /// <param name="argSender">Unused</param>
        /// <param name="argEventArgs">Unused</param>
        private void contextMenuItemSelectAllFiles_Click(object argSender, EventArgs argEventArgs)
        {
            SelectAllFiles();
        }


        /// <summary>
        /// Select all the subdirectories in this directory.
        /// </summary>
        /// <param name="argSender">Unused</param>
        /// <param name="argEventArgs">Unused</param>
        private void contextMenuItemSelectAllDirectories_Click(object argSender, EventArgs argEventArgs)
        {
            SelectAllDirectories();
        }

        /// <summary>
        /// Clear any selection of files or directories.
        /// </summary>
        /// <param name="argSender">Unused</param>
        /// <param name="argEventArgs">Unused</param>
        private void contextMenuItemClearSelection_Click(object argSender, EventArgs argEventArgs)
        {
            ClearSelection();
        }

        private void contextMenuItemProperties_Click(object argSender, EventArgs argEventArgs)
        {
            using (FormFileProperties propertiesForm = new FormFileProperties(_selectedFileItems[0].ToFileListViewItem()))
            {
                propertiesForm.ShowDialog(this);
            }
        }

        private void contextMenuItemZip_Click(object argSender, EventArgs argEventArgs)
        {
            List<String> itemList = new List<string>();

            if (String.IsNullOrWhiteSpace(_zipFullPathName))
            { return; }

            itemList.AddRange(_selectedFileItems.FilenameList);
            itemList.AddRange(_selectedDirectoryItems.FilenameList);

            if (File.Exists(_zipFullPathName))
            {
                ZipWrapper.UpdateExistingZip(_zipFullPathName, null, itemList);
            }
            else
            {
                ZipWrapper.CreateZipFile(_zipFullPathName, null, itemList);
            }

        }

        /// <summary>
        /// Selects all File items in the current view.
        /// </summary>
        public void SelectAllFiles()
        {
            _selectedFileItems.Clear();

            foreach (FileSystemListViewItem currentItem in Items)
            {
                //currentItem.IsMarked = true;
                if (currentItem is FileListViewItem)
                {
                    _selectedFileItems.Add((FileListViewItem)currentItem);

                    Invalidate(currentItem.Bounds);
                }
            }
        }

        /// <summary>
        /// Selects all Directory items in the current view.
        /// </summary>
        public void SelectAllDirectories()
        {
            _selectedDirectoryItems.Clear();

            foreach (FileSystemListViewItem currentItem in Items)
            {
                //Doubly-not needed. DotDotDirectories are now different objects than regular directories.
                ////if (CurrentItem.IsDotDot)
                //if (CurrentItem is DotDotListViewItem)
                //    continue;

                //currentItem.IsMarked = true;
                DirectoryListViewItem dirItem = currentItem as DirectoryListViewItem;
                if (dirItem != null)
                {
                    _selectedDirectoryItems.Add(dirItem);

                    Invalidate(dirItem.Bounds);
                }
            }
        }

        /// <summary>
        /// Selects all items in the current view, regardless of type.
        /// </summary>
        public void SelectAllItems()
        {
            _selectedFileItems.Clear();
            _selectedDirectoryItems.Clear();
            foreach (FileSystemListViewItem currentItem in Items)
            {
                //Doubly not-needed. DotDotListViewItems are different than either of the other filesystem objects.
                ////if (CurrentItem.IsDotDot)
                //if (CurrentItem is DotDotListViewItem)
                //    continue;

                //currentItem.IsMarked = true;
                FileListViewItem fileItem = currentItem as FileListViewItem;
                if (fileItem != null)
                {
                    _selectedFileItems.Add(fileItem);
                }
                else
                {
                    DirectoryListViewItem dirItem = currentItem as DirectoryListViewItem;
                    if (dirItem != null)
                    {
                        _selectedDirectoryItems.Add(dirItem);
                    }
                }
            }

            Invalidate(true);
        }

        /// <summary>
        /// Clears any selections.
        /// </summary>
        public void ClearSelection()
        {
            //ClearSelection needs to clear IsMarked
            //foreach (FileListViewItem CurrentItem in _selectedFileItems)
            //{
            //    CurrentItem.IsMarked = false;
            //}
            //foreach (DirectoryListViewItem CurrentItem in _selectedDirectoryItems)
            //{
            //    CurrentItem.IsMarked = false;
            //}

            _selectedFileItems.Clear();
            _selectedDirectoryItems.Clear();

            Invalidate(true);
        }

        /// <summary>
        /// Reloads items based on the state of the current path.
        /// </summary>
        public void RefreshPath()
        {
            if (_refreshing)
            {
                return;
            }

            _refreshing = true;

            if (_currentPath.Length <= 0)
            {
                _refreshing = false;
                return;
            }

            SetPath(_currentPath);

            Invalidate(ClientRectangle);
            _refreshing = false;
        }

        /// <summary>
        /// Suspends DirectoryWatching. Used before tasks that can affect the contents of the current path so we don't cause an infinite loop.
        /// </summary>
        //public void SuspendWatching()
        //{
        //    if (_directoryWatcher != null)
        //    {
        //        _directoryWatcher.EnableRaisingEvents = false;
        //    }
        //}
        /// <summary>
        /// Restart DirectoryWatching.
        /// </summary>
        //public void ResumeWatching()
        //{
        //    RefreshPath();
        //    Application.DoEvents();
        //}
 
        #endregion

        #region ** Private Methods **

        #region ** Context Menu **

        /// <summary>
        /// Sorts out which items to display based on what FSLVI objects are selected.
        /// </summary>
        /// <param name="argSender">Unused</param>
        /// <param name="argEventArgs">Unused</param>
        private void contextMenuStripRightClick_Opening(object argSender, CancelEventArgs argEventArgs)
        {
            try
            {
                _contextMenuItemNothingSelected.Visible = true;

                _contextMenuItemDirSpace.Visible = false;
                _contextMenuItemOpenWith.Visible = false;
                _contextMenuItemRename.Visible = false;
                _contextMenuItemProperties.Visible = false;

                _contextMenuItemDuplicate.Visible = false;
                _contextMenuItemDuplicateDirectory.Visible = false;
                _contextMenuItemDuplicateFile.Visible = false;

                _contextMenuClipboard.Visible = false;
                _contextMenuCopyNameToClipboard.Visible = true;
                _contextMenuCopyPathToClipboard.Visible = true;
                _contextMenuCopyFullPathToClipboard.Visible = true;

                _contextMenuItemSelect.Visible = true;
                _contextMenuItemSelectAllDirectories.Visible = true;
                _contextMenuItemSelectAllFiles.Visible = true;
                _contextMenuItemClearSelection.Visible = false;
                _contextMenuItemZip.Visible = false;


                //Get current selection
                if (SelectedItems.Count <= 0)
                {
                    return;
                }

                _contextMenuItemClearSelection.Visible = true;
                //_contextMenuItemDirSpace.Visible = false;
                //_contextMenuItemDuplicateDirectory.Visible = false;
                //_contextMenuItemDuplicateFile.Visible = false;
                _contextMenuClipboard.Visible = true;
                //_contextMenuCopyNameToClipboard.Visible = true;
                //_contextMenuCopyPathToClipboard.Visible = true;
                //_contextMenuCopyFullPathToClipboard.Visible = true;
                _contextMenuItemNothingSelected.Visible = false;
                //_contextMenuItemOpenWith.Visible = false;
                _contextMenuItemRename.Visible = true;
                //_contextMenuItemSelectAllDirectories.Visible = false;
                //_contextMenuItemSelectAllFiles.Visible = false;                
                //_contextMenuItemProperties.Visible = false;

                if (_selectedFileItems.Count > 0)
                {
                    _contextMenuItemDuplicate.Visible = true;
                    _contextMenuItemOpenWith.Visible = true;
                    _contextMenuItemDuplicateFile.Visible = true;
                    _contextMenuItemProperties.Visible = true;

                    string zipFileName = _selectedFileItems[0].RootName + ".zip";
                    _zipFullPathName = _selectedFileItems[0].Path + "\\" + zipFileName;

                    if (File.Exists(_selectedFileItems[0].Path + "\\" + zipFileName))
                    {
                        _contextMenuItemZip.Text = @"Add to Zip " + zipFileName;
                    }
                    else
                    {
                        _contextMenuItemZip.Text = @"Zip to " + zipFileName;
                    }

                    _contextMenuItemZip.Visible = true;

                }

                if (_selectedDirectoryItems.Count > 0)
                {
                    _contextMenuItemDuplicate.Visible = true;
                    _contextMenuItemDirSpace.Visible = true;
                    _contextMenuItemDuplicateDirectory.Visible = true;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(@"Error in contextMenuStripRightClick_Opening: " + ex.Message);
            }
        }

        #endregion

        #region ** Drag/Drop events **

        /// <summary>
        /// Override of the ItemDrag event.
        /// </summary>
        /// <param name="argEventArgs">Information about the specific drag event.</param>
        protected override void OnItemDrag(ItemDragEventArgs argEventArgs)
        {
            //When the item is starting to be dragged
            //Happens first when Dragging an Item

            if (SelectedItems.Count <= 0)
            {
                return;
            }

            //Create list of filenames
            List<string> fileNames = new List<string>();
            StringCollection fileList = new StringCollection();

            foreach (FileSystemListViewItem currentItem in SelectedItems)
            {
                fileList.Add(currentItem.FullPath);
            }

            //Create DataObject structures to use during drag.
            DataObject tempDataObject = new DataObject();

            tempDataObject.SetFileDropList(fileList);

            base.OnItemDrag(argEventArgs);
            DoDragDrop(tempDataObject, DragDropEffects.All);
        }

        /// <summary>
        /// Raises the System.Windows.Forms.Control.DragEnter event
        /// </summary>
        /// <param name="argDrgevent">A System.Windows.Forms.DragEventArgs that contains the event data.</param>
        /// <remarks>Happens when Item enters drag area (including items from the current listview).
        /// Happens second, on the source view, when dragging an item.</remarks>
        protected override void OnDragEnter(DragEventArgs argDrgevent)
        {
            List<string> lstTest = new List<string>(argDrgevent.Data.GetFormats());

            if (lstTest.Contains("FileDrop"))
            {
                argDrgevent.Effect = (argDrgevent.KeyState & 8) == 8 ? DragDropEffects.Copy : DragDropEffects.Move;

                base.OnDragEnter(argDrgevent);
                return;
            }

            argDrgevent.Effect = DragDropEffects.None;
        }

        //MouseOver with dragitem attached
        //Happens third when dragging an item
        protected override void OnDragOver(DragEventArgs argDrgevent)
        {
            //Happens often during the dragging

            argDrgevent.Effect = (argDrgevent.KeyState & 8) == 8 ? DragDropEffects.Copy : DragDropEffects.Move;

            _rmbDown = (argDrgevent.KeyState & 2) == 2;

            base.OnDragOver(argDrgevent);
        }

        //When DragItem is actually dropped
        protected override void OnDragDrop(DragEventArgs argDrgevent)
        {
            try
            {
                DataObject testDataObject = new DataObject(argDrgevent.Data);

                //if (ItemFormats.Contains("FileDrop"))
                //if (ItemFormats.Contains("Shell IDList Array"))
                if (testDataObject.ContainsFileDropList())
                {
                    _fileNames.Clear();

                    StringCollection testCollection = testDataObject.GetFileDropList();

                    string[] utilStringArr = new string[testCollection.Count];
                    testCollection.CopyTo(utilStringArr, 0);
                    _fileNames.AddRange(utilStringArr);

                    if (_rmbDown)
                    {
                        _dragDropMenu.Show(MousePosition);
                        return;
                    }

                    if ((argDrgevent.KeyState & 8) == 8)
                    {
                        CopyItems(_fileNames);
                    }
                    else
                    {
                        MoveItems(_fileNames);
                    }
                }

                base.OnDragDrop(argDrgevent);
            }
            catch (Exception)
            {
                //MessageBox.Show("Error while dropping file.", "Drag/Drop error");
                Cursor = Cursors.Default;
            }
        }

        #endregion

        #region ** Overridden events **

        protected override void OnLostFocus(EventArgs argEventArgs)
        {
            base.OnLostFocus(argEventArgs);

            if (DesignMode)
            {
                return;
            }

            _hasFocus = false;
            Invalidate(true);
        }

        protected override void OnGotFocus(EventArgs argEventArgs)
        {
            base.OnGotFocus(argEventArgs);

            if (DesignMode)
            {
                return;
            }

            _hasFocus = true;

            Invalidate(true);
        }

        protected override void OnClientSizeChanged(EventArgs argEventArgs)
        {
            base.OnClientSizeChanged(argEventArgs);

            Invalidate(true); //This makes sure the items get painted after a change in size.
        }

        protected override void OnColumnWidthChanged(ColumnWidthChangedEventArgs argEventArgs)
        {
            base.OnColumnWidthChanged(argEventArgs);

            if (DesignMode)
            {
                return;
            }

            //StreamWriter logwriter = File.AppendText(@"C:\$hank\Projects\FileTracker\FileTracker\bin\Debug\LogFile.txt");
            //logwriter.WriteLine("OnColumnWidthChanged\r\n");
            //logwriter.Close();


            _plainColumnPaintBrushes[0] = null;
            _plainColumnPaintBrushes[1] = null;
            _plainColumnPaintBrushes[2] = null;

            _highlightColumnPaintBrushes[0] = null;
            _highlightColumnPaintBrushes[1] = null;
            _highlightColumnPaintBrushes[2] = null;

            _plainFilePaintBrushes[0] = null;
            _plainFilePaintBrushes[1] = null;
            _plainFilePaintBrushes[2] = null;

            _selectedFilePaintBrushes[0] = null;
            _selectedFilePaintBrushes[1] = null;
            _selectedFilePaintBrushes[2] = null;

            _mouseOverFilePaintBrushes[0] = null;
            _mouseOverFilePaintBrushes[1] = null;
            _mouseOverFilePaintBrushes[2] = null;

            _selectedMouseOverFilePaintBrushes[0] = null;
            _selectedMouseOverFilePaintBrushes[1] = null;
            _selectedMouseOverFilePaintBrushes[2] = null;

            _plainDirectoryPaintBrushes[0] = null;
            _plainDirectoryPaintBrushes[1] = null;
            _plainDirectoryPaintBrushes[2] = null;

            _selectedDirectoryPaintBrushes[0] = null;
            _selectedDirectoryPaintBrushes[1] = null;
            _selectedDirectoryPaintBrushes[2] = null;

            _mouseOverDirectoryPaintBrushes[0] = null;
            _mouseOverDirectoryPaintBrushes[1] = null;
            _mouseOverDirectoryPaintBrushes[2] = null;

            _selectedMouseOverDirectoryPaintBrushes[0] = null;
            _selectedMouseOverDirectoryPaintBrushes[1] = null;
            _selectedMouseOverDirectoryPaintBrushes[2] = null;
        }

        protected override void OnDrawSubItem(DrawListViewSubItemEventArgs argEventArgs)
        {
            StringFormat sf = null;

            if (argEventArgs.Bounds.IsEmpty)
            {
                //Logger.LogInfo("OnDrawSubItem - argBounds is Empty");
                return;
            }

            try
            {
                FileSystemListViewItem currentItem = (FileSystemListViewItem)argEventArgs.Item;
                //if (CurrentItem.FullPath.StartsWith("K:"))
                //{
                //    for (int iLoop = 0; iLoop < 2234567; iLoop++)
                //    { }
                //}

                //using (StreamWriter logwriter = File.AppendText(@"C:\$hank\Projects\FileTracker\FileTracker\bin\Debug\LogFile.txt"))
                //{
                //    logwriter.WriteLine("OnDrawSubItem " + this.Name + " - " + CurrentItem.Text + "\r\n");
                //logwriter.Close();
                //logwriter.WriteLine("Early bounds check - " + argEventArgs.argBounds.ToString() + "\r\n");

                sf = new StringFormat
                    {
                        Alignment = argEventArgs.ColumnIndex == 0 ? StringAlignment.Near : StringAlignment.Far,
                        Trimming = StringTrimming.EllipsisCharacter,
                        FormatFlags = StringFormatFlags.LineLimit | StringFormatFlags.NoWrap
                    };
                //logwriter.WriteLine("OnDrawSubItem - sf.Alignment - " + argEventArgs.ColumnIndex + "\r\n");

                //Flags include                    ^^                            ^^^
                //Limit formatting to stop after a line is done    |            Don't wordwrap;

                if (_plainFilePaintBrushes[argEventArgs.ColumnIndex] == null)
                {
                    RebuildItemBrushes(argEventArgs.ColumnIndex, argEventArgs.Bounds);
                }

                SolidBrush currentTextBrush;
                LinearGradientBrush brush;
                Font currentFont;
                if (currentItem.IsMarked && currentItem.IsMouseOver)
                {
                    if (currentItem is FileListViewItem)
                    {
                        brush = _selectedMouseOverFilePaintBrushes[argEventArgs.ColumnIndex];
                        currentTextBrush = _selectedMouseOverFileFontBrush;
                        currentFont = _fileSettings.SelectedMouseOverSettings.Font; //_selectedMouseOverFileFont;
                    }
                    else
                    {
                        brush = _selectedMouseOverDirectoryPaintBrushes[argEventArgs.ColumnIndex];
                        currentTextBrush = _selectedMouseOverDirectoryFontBrush;
                        currentFont = _directorySettings.SelectedMouseOverSettings.Font; //_selectedMouseOverDirectoryFont;
                    }
                }
                else if (currentItem.IsMarked) //Not MouseOver is filtered out from above
                {
                    if (currentItem is FileListViewItem)
                    {
                        brush = _selectedFilePaintBrushes[argEventArgs.ColumnIndex];
                        currentTextBrush = _selectedFileFontBrush;
                        currentFont = _fileSettings.SelectedSettings.Font; // _selectedFileFont;
                    }
                    else
                    {
                        brush = _selectedDirectoryPaintBrushes[argEventArgs.ColumnIndex];
                        currentTextBrush = _selectedDirectoryFontBrush;
                        currentFont = _directorySettings.SelectedSettings.Font; // _selectedDirectoryFont;
                    }
                }
                else if (currentItem.IsMouseOver) //Not Marked is filtered out from above
                {
                    if (currentItem is FileListViewItem)
                    {
                        brush = _mouseOverFilePaintBrushes[argEventArgs.ColumnIndex];
                        currentTextBrush = _mouseOverFileFontBrush;
                        currentFont = _fileSettings.MouseOverSettings.Font; // _mouseOverFileFont;
                    }
                    else
                    {
                        brush = _mouseOverDirectoryPaintBrushes[argEventArgs.ColumnIndex];
                        currentTextBrush = _mouseOverDirectoryFontBrush;
                        currentFont = _directorySettings.MouseOverSettings.Font; // _mouseOverDirectoryFont;
                    }
                }
                else
                {
                    if (currentItem is FileListViewItem)
                    {
                        brush = _plainFilePaintBrushes[argEventArgs.ColumnIndex];
                        currentTextBrush = _plainFileFontBrush;
                        currentFont = _fileSettings.PlainSettings.Font; // _plainFileFont;
                    }
                    else
                    {
                        brush = _plainDirectoryPaintBrushes[argEventArgs.ColumnIndex];
                        currentTextBrush = _plainDirectoryFontBrush;
                        currentFont = _directorySettings.PlainSettings.Font; // _plainDirectoryFont;
                    }
                }

                if (currentTextBrush == null)
                {
                    currentTextBrush = _plainFileFontBrush;
                }

                if (brush != null)
                {
                    argEventArgs.Graphics.FillRectangle(brush, argEventArgs.Bounds);
                }

                Rectangle stringRectangle = new Rectangle(argEventArgs.Bounds.Location, argEventArgs.Bounds.Size);

                if ((argEventArgs.ColumnIndex == 0) && (currentItem.SmallIcon != null))
                {
                    //Draw the icon
                    argEventArgs.Graphics.DrawIconUnstretched(currentItem.SmallIcon, argEventArgs.Bounds);

                    //Move the text over
                    stringRectangle.Offset(currentItem.SmallIcon.Width + 1, 0);
                    stringRectangle.Width = stringRectangle.Width - (currentItem.SmallIcon.Width + 1);
                }
                //logwriter.WriteLine("Late bounds check - " + argEventArgs.argBounds.ToString() + "\r\n");
                argEventArgs.Graphics.DrawString(argEventArgs.SubItem.Text, currentFont, currentTextBrush, stringRectangle, sf);

                //}
            }
            finally
            {
                if (sf != null)
                {
                    sf.Dispose();
                }
            }
        }

        protected override void OnDrawColumnHeader(DrawListViewColumnHeaderEventArgs argEventArgs)
        {
            //StreamWriter logwriter = File.AppendText(@"C:\$hank\Projects\FileTracker\FileTracker\bin\Debug\LogFile.txt");
            //logwriter.WriteLine("OnDrawColumnHeader - " + this.Name + " - " + argEventArgs.Header.Text + "\r\n");
            //logwriter.Close();

            LinearGradientBrush brush = null; // _plainColumnPaintBrushes[0];

            if (argEventArgs.Bounds.IsEmpty)
            {
                return;
            }

            if (_plainColumnPaintBrushes[argEventArgs.ColumnIndex] == null)
            {
                RebuildColumnBrushes(argEventArgs.ColumnIndex, argEventArgs.Bounds);
            }

            //TODO: 009 - Investigate: Can this be changed to use _sortColumn as an index?
            //if(argEventArgs.ColumnIndex == _sortColumn )
            //{
            //   brush = _highlightColumnPaintBrushes[argEventArgs.ColumnIndex];
            //} else {
            //   brush = _plainColumnPaintBrushes[argEventArgs.ColumnIndex];
            //}
            switch (argEventArgs.ColumnIndex)
            {
                case 0:
                    brush = _sortColumn == 0 ? _highlightColumnPaintBrushes[0] : _plainColumnPaintBrushes[0];
                    break;
                case 1:
                    brush = _sortColumn == 1 ? _highlightColumnPaintBrushes[1] : _plainColumnPaintBrushes[1];
                    break;
                case 2:
                    brush = _sortColumn == 2 ? _highlightColumnPaintBrushes[2] : _plainColumnPaintBrushes[2];
                    break;
            }

            if (brush != null)
            {
                argEventArgs.Graphics.FillRectangle(brush, argEventArgs.Bounds);
            }

            if (_hasFocus)
            {
                using (SolidBrush localFocusColor = new SolidBrush(_focusColor))
                {
                    argEventArgs.Graphics.FillRectangle(localFocusColor, 0, 0, DisplayRectangle.Width, 3);
                }
            }

            //SolidBrush ColumnTextBrush = new SolidBrush(_columnForeColor);
            using (SolidBrush columnTextBrush = new SolidBrush(_columnSettings.PlainSettings.FontColor))
            {
                using (StringFormat sf = new StringFormat())
                {
                    // Draw the header text.
                    //argEventArgs.Graphics.DrawString(argEventArgs.Header.Text, _columnFont, ColumnTextBrush, argEventArgs.argBounds, sf);
                    argEventArgs.Graphics.DrawString(argEventArgs.Header.Text, _columnSettings.PlainSettings.Font, columnTextBrush, argEventArgs.Bounds, sf);
                }
            }
        }

        private void RebuildColumnBrushes(int argColumnIndex, Rectangle argBounds)
        {
            Color highlightColor1;
            Color highlightColor2;
            Color color1;
            Color color2;
            float highlightGradientAngle;
            float gradientAngle;

            switch (argColumnIndex)
            {
                case 0:

                    highlightColor1 = _columnSettings.HighlightSettings.NameColors.Color1; // _highlightColumnNameColor1;
                    highlightColor2 = _columnSettings.HighlightSettings.NameColors.Color2; //_highlightColumnNameColor2;

                    highlightGradientAngle = _columnSettings.HighlightSettings.NameColors.Direction; //_highlightColumnNameColorDirection;

                    //_highlightColumnPaintBrushes[0] = new LinearGradientBrush(argBounds, Color1, Color2, GradientAngle);

                    color1 = _columnSettings.PlainSettings.NameColors.Color1; // _plainColumnNameColor1;
                    color2 = _columnSettings.PlainSettings.NameColors.Color2; //_plainColumnNameColor2;

                    gradientAngle = _columnSettings.PlainSettings.NameColors.Direction; //_plainColumnNameColorDirection;

                    //_plainColumnPaintBrushes[0] = new LinearGradientBrush(argBounds, Color1, Color2, GradientAngle);
                    break;
                case 1:

                    highlightColor1 = _columnSettings.HighlightSettings.SizeColors.Color1; //_highlightColumnSizeColor1;
                    highlightColor2 = _columnSettings.HighlightSettings.SizeColors.Color2; //_highlightColumnSizeColor2;

                    highlightGradientAngle = _columnSettings.HighlightSettings.SizeColors.Direction; //_highlightColumnSizeColorDirection;

                    //_highlightColumnPaintBrushes[1] = new LinearGradientBrush(argBounds, Color1, Color2, GradientAngle);


                    color1 = _columnSettings.PlainSettings.SizeColors.Color1; // _plainColumnSizeColor1;
                    color2 = _columnSettings.PlainSettings.SizeColors.Color2; // _plainColumnSizeColor2;

                    gradientAngle = _columnSettings.PlainSettings.SizeColors.Direction; // _plainColumnSizeColorDirection;
                    //_plainColumnPaintBrushes[1] = new LinearGradientBrush(argBounds, Color1, Color2, GradientAngle);
                    break;

                case 2:
                    highlightColor1 = _columnSettings.HighlightSettings.DateColors.Color1; //_highlightColumnDateColor1;
                    highlightColor2 = _columnSettings.HighlightSettings.DateColors.Color2; //_highlightColumnDateColor2;

                    highlightGradientAngle = _columnSettings.HighlightSettings.DateColors.Direction; //_highlightColumnDateColorDirection;
                    //_highlightColumnPaintBrushes[2] = new LinearGradientBrush(argBounds, Color1, Color2, GradientAngle);


                    color1 = _columnSettings.PlainSettings.DateColors.Color1; //_plainColumnDateColor1;
                    color2 = _columnSettings.PlainSettings.DateColors.Color2; //_plainColumnDateColor2;

                    gradientAngle = _columnSettings.PlainSettings.DateColors.Direction; //_plainColumnDateColorDirection;
                    //_plainColumnPaintBrushes[2] = new LinearGradientBrush(argBounds, Color1, Color2, GradientAngle);
                    break;
                default:
                    highlightColor1 = Color.White;
                    highlightColor2 = Color.White;
                    color1 = Color.White;
                    color2 = Color.White;
                    highlightGradientAngle = 0.0f;
                    gradientAngle = 0.0f;
                    break;
            }

            _highlightColumnPaintBrushes[argColumnIndex] = new LinearGradientBrush(argBounds, highlightColor1, highlightColor2, highlightGradientAngle);
            _plainColumnPaintBrushes[argColumnIndex] = new LinearGradientBrush(argBounds, color1, color2, gradientAngle);
        }

        private void RebuildItemBrushes(int argColumnIndex, Rectangle argBounds)
        {
            //Set column specific values
            switch (argColumnIndex)
            {
                case 0: //Name
                    //Selected MouseOver Color
                    _selectedMouseOverFilePaintBrushes[0] = new LinearGradientBrush(argBounds, _fileSettings.SelectedMouseOverSettings.NameColors.Color1, _fileSettings.SelectedMouseOverSettings.NameColors.Color2, _fileSettings.SelectedMouseOverSettings.NameColors.Direction);

                    //Selected Item Color
                    _selectedFilePaintBrushes[0] = new LinearGradientBrush(argBounds, _fileSettings.SelectedSettings.NameColors.Color1, _fileSettings.SelectedSettings.NameColors.Color2, _fileSettings.SelectedSettings.NameColors.Direction);

                    //Item MouseOver Color
                    _mouseOverFilePaintBrushes[0] = new LinearGradientBrush(argBounds, _fileSettings.MouseOverSettings.NameColors.Color1, _fileSettings.MouseOverSettings.NameColors.Color2, _fileSettings.MouseOverSettings.NameColors.Direction);

                    //Item Color
                    _plainFilePaintBrushes[0] = new LinearGradientBrush(argBounds, _fileSettings.PlainSettings.NameColors.Color1, _fileSettings.PlainSettings.NameColors.Color2, _fileSettings.PlainSettings.NameColors.Direction);

                    //Selected MouseOver Color
                    _selectedMouseOverDirectoryPaintBrushes[0] = new LinearGradientBrush(argBounds, _directorySettings.SelectedMouseOverSettings.NameColors.Color1, _directorySettings.SelectedMouseOverSettings.NameColors.Color2, _directorySettings.SelectedMouseOverSettings.NameColors.Direction);

                    //Selected Item Color
                    _selectedDirectoryPaintBrushes[0] = new LinearGradientBrush(argBounds, _directorySettings.SelectedSettings.NameColors.Color1, _directorySettings.SelectedSettings.NameColors.Color2, _directorySettings.SelectedSettings.NameColors.Direction);

                    //Item MouseOver Color
                    _mouseOverDirectoryPaintBrushes[0] = new LinearGradientBrush(argBounds, _directorySettings.MouseOverSettings.NameColors.Color1, _directorySettings.MouseOverSettings.NameColors.Color2, _directorySettings.MouseOverSettings.NameColors.Direction);

                    //Item Color
                    _plainDirectoryPaintBrushes[0] = new LinearGradientBrush(argBounds, _directorySettings.PlainSettings.NameColors.Color1, _directorySettings.PlainSettings.NameColors.Color2, _directorySettings.PlainSettings.NameColors.Direction);

                    break;
                case 1: //Size

                    //Selected MouseOver Color
                    _selectedMouseOverFilePaintBrushes[1] = new LinearGradientBrush(argBounds, _fileSettings.SelectedMouseOverSettings.SizeColors.Color1, _fileSettings.SelectedMouseOverSettings.SizeColors.Color2, _fileSettings.SelectedMouseOverSettings.SizeColors.Direction);

                    //Selected Item Color
                    _selectedFilePaintBrushes[1] = new LinearGradientBrush(argBounds, _fileSettings.SelectedSettings.SizeColors.Color1, _fileSettings.SelectedSettings.SizeColors.Color2, _fileSettings.SelectedSettings.SizeColors.Direction);

                    //Item MouseOver Color
                    _mouseOverFilePaintBrushes[1] = new LinearGradientBrush(argBounds, _fileSettings.MouseOverSettings.SizeColors.Color1, _fileSettings.MouseOverSettings.SizeColors.Color2, _fileSettings.MouseOverSettings.SizeColors.Direction);

                    //Item Color
                    _plainFilePaintBrushes[1] = new LinearGradientBrush(argBounds, _fileSettings.PlainSettings.SizeColors.Color1, _fileSettings.PlainSettings.SizeColors.Color2, _fileSettings.PlainSettings.SizeColors.Direction);

                    //Selected MouseOver Color
                    _selectedMouseOverDirectoryPaintBrushes[1] = new LinearGradientBrush(argBounds, _directorySettings.SelectedMouseOverSettings.SizeColors.Color1, _directorySettings.SelectedMouseOverSettings.SizeColors.Color2, _directorySettings.SelectedMouseOverSettings.SizeColors.Direction);

                    //Selected Item Color
                    _selectedDirectoryPaintBrushes[1] = new LinearGradientBrush(argBounds, _directorySettings.SelectedSettings.SizeColors.Color1, _directorySettings.SelectedSettings.SizeColors.Color2, _directorySettings.SelectedSettings.SizeColors.Direction);

                    //Item MouseOver Color
                    _mouseOverDirectoryPaintBrushes[1] = new LinearGradientBrush(argBounds, _directorySettings.MouseOverSettings.SizeColors.Color1, _directorySettings.MouseOverSettings.SizeColors.Color2, _directorySettings.MouseOverSettings.SizeColors.Direction);

                    //Item Color
                    _plainDirectoryPaintBrushes[1] = new LinearGradientBrush(argBounds, _directorySettings.PlainSettings.SizeColors.Color1, _directorySettings.PlainSettings.SizeColors.Color2, _directorySettings.PlainSettings.SizeColors.Direction);

                    break;
                case 2: //Date
                    //Selected MouseOver Color
                    _selectedMouseOverFilePaintBrushes[2] = new LinearGradientBrush(argBounds, _fileSettings.SelectedMouseOverSettings.DateColors.Color1, _fileSettings.SelectedMouseOverSettings.DateColors.Color2, _fileSettings.SelectedMouseOverSettings.DateColors.Direction);

                    //Selected Item Color
                    _selectedFilePaintBrushes[2] = new LinearGradientBrush(argBounds, _fileSettings.SelectedSettings.DateColors.Color1, _fileSettings.SelectedSettings.DateColors.Color2, _fileSettings.SelectedSettings.DateColors.Direction);

                    //Item MouseOver Color
                    _mouseOverFilePaintBrushes[2] = new LinearGradientBrush(argBounds, _fileSettings.MouseOverSettings.DateColors.Color1, _fileSettings.MouseOverSettings.DateColors.Color2, _fileSettings.MouseOverSettings.DateColors.Direction);

                    //Item Color
                    _plainFilePaintBrushes[2] = new LinearGradientBrush(argBounds, _fileSettings.PlainSettings.DateColors.Color1, _fileSettings.PlainSettings.DateColors.Color2, _fileSettings.PlainSettings.DateColors.Direction);

                    /****/
                    //Selected MouseOver Color
                    _selectedMouseOverDirectoryPaintBrushes[2] = new LinearGradientBrush(argBounds, _directorySettings.SelectedMouseOverSettings.DateColors.Color1, _directorySettings.SelectedMouseOverSettings.DateColors.Color2, _directorySettings.SelectedMouseOverSettings.DateColors.Direction);

                    //Selected Item Color
                    _selectedDirectoryPaintBrushes[2] = new LinearGradientBrush(argBounds, _directorySettings.SelectedSettings.DateColors.Color1, _directorySettings.SelectedSettings.DateColors.Color2, _directorySettings.SelectedSettings.DateColors.Direction);

                    //Item MouseOver Color
                    _mouseOverDirectoryPaintBrushes[2] = new LinearGradientBrush(argBounds, _directorySettings.MouseOverSettings.DateColors.Color1, _directorySettings.MouseOverSettings.DateColors.Color2, _directorySettings.MouseOverSettings.DateColors.Direction);

                    //Item Color
                    _plainDirectoryPaintBrushes[2] = new LinearGradientBrush(argBounds, _directorySettings.PlainSettings.DateColors.Color1, _directorySettings.PlainSettings.DateColors.Color2, _directorySettings.PlainSettings.DateColors.Direction);

                    break;
            }

            //_selectedMouseOverFileFontBrush = new SolidBrush(_selectedMouseOverFileForeColor);
            _selectedMouseOverFileFontBrush = new SolidBrush(_fileSettings.SelectedMouseOverSettings.FontColor);
            //_selectedFileFontBrush = new SolidBrush(_selectedFileForeColor);
            _selectedFileFontBrush = new SolidBrush(_fileSettings.SelectedSettings.FontColor);
            //_mouseOverFileFontBrush = new SolidBrush(_mouseOverFileForeColor);
            _mouseOverFileFontBrush = new SolidBrush(_fileSettings.MouseOverSettings.FontColor);
            //_plainFileFontBrush = new SolidBrush(_plainFileForeColor);
            _plainFileFontBrush = new SolidBrush(_fileSettings.PlainSettings.FontColor);

            //_selectedMouseOverDirectoryFontBrush = new SolidBrush(_selectedMouseOverDirectoryForeColor);
            _selectedMouseOverDirectoryFontBrush = new SolidBrush(_directorySettings.SelectedMouseOverSettings.FontColor);
            //_selectedDirectoryFontBrush = new SolidBrush(_selectedDirectoryForeColor);
            _selectedDirectoryFontBrush = new SolidBrush(_directorySettings.SelectedSettings.FontColor);
            //_mouseOverDirectoryFontBrush = new SolidBrush(_mouseOverDirectoryForeColor);
            _mouseOverDirectoryFontBrush = new SolidBrush(_directorySettings.MouseOverSettings.FontColor);
            //_plainDirectoryFontBrush = new SolidBrush(_plainDirectoryForeColor);
            _plainDirectoryFontBrush = new SolidBrush(_directorySettings.PlainSettings.FontColor);
        }

        protected override void OnMouseClick(MouseEventArgs argEventArgs)
        {
            {
                //_log.Debug("Check if the click was a right-click");
                if (argEventArgs.Button == MouseButtons.Right)
                {
                    return;
                }

                //_log.Debug("Get the item that was clicked (if any)");
                //Use HitTest for better performance.
                ListViewHitTestInfo clickedInfo = HitTest(PointToClient(MousePosition));

                FileSystemListViewItem clickedItem = clickedInfo.Item as FileSystemListViewItem;
                if (clickedItem == null)
                {
                    return;
                }

                //TODO: 019 - Add "accessDenied" flag to FileSystemListViewItem
                if (clickedItem.Text == @"* Access Denied *")
                {
                    return;
                }

                //_log.Debug("Check if the item is a file...");
                FileListViewItem fileItem = clickedItem as FileListViewItem;
                if (fileItem != null)
                {
                    if (fileItem.IsMarked)
                    {
                        //_log.Debug("Remove the file from selected.");
                        _selectedFileItems.Remove(fileItem);
                    }
                    else
                    {
                        //_log.Debug("Add the file to selected.");
                        _selectedFileItems.Add(fileItem);
                    }
                    //fileItem.IsMarked = !fileItem.IsMarked;
                }
                else
                {
                    //_log.Debug("Check if the item is a directory...");
                    DirectoryListViewItem dirItem = clickedItem as DirectoryListViewItem;
                    if (dirItem != null)
                    {
                        if (dirItem.IsMarked)
                        {
                            //_log.Debug("Remove the directory from selected");
                            _selectedDirectoryItems.Remove(dirItem);
                        }
                        else
                        {
                            //_log.Debug("Add the directory to selected");
                            _selectedDirectoryItems.Add(dirItem);
                        }
                        //dirItem.IsMarked = !dirItem.IsMarked;
                    }
                }

                Invalidate(clickedItem.Bounds);
            }
        }

        protected override void OnMouseMove(MouseEventArgs argEventArgs)
        {
            base.OnMouseMove(argEventArgs);
            if (DesignMode)
            {
                return;
            }

            //Get the current item
            FileSystemListViewItem currentItem = (FileSystemListViewItem)GetItemAt(5, argEventArgs.Y);
            //_logFile.WriteLine("\tempReader\nMouseOver at: 5," + argEventArgs.Y.ToString() + " @ " + DateTime.Now.ToLongTimeString() );

            //if it's a valid item
            if (currentItem != null)
            {
                //Check if the popup rectangle is being displayed
                //!!!This is not how to test for rectangle being displayed.!!!
                if (!_itemPopupRectangle.IsEmpty)
                {
                    _itemPopupRectangle = Rectangle.Empty;
                    //this.Invalidate(_itemPopupRectangle);
                }

                //Check if the item already has the mouse over it.
                if (currentItem == _oldItemMouseOver)
                {
                    return;
                }

                //Check if the old MouseOver item was null and set it to the current item if needs be
                if (_oldItemMouseOver == null)
                {
                    //Set the new item as the MouseOver Item
                    currentItem.IsMouseOver = true;

                    //Se the current item as the old item and wait for the next event
                    _oldItemMouseOver = currentItem;
                    return;
                }

                //Clear the old MouseOver Item first incase the mouse just moved sideways
                _oldItemMouseOver.IsMouseOver = false;


                //Redraw the old item first in case the new item paints over it.
                Invalidate(_oldItemMouseOver.Bounds);

                //Set the new item as the MouseOver Item
                currentItem.IsMouseOver = true;

                //Now paint the new item
                Invalidate(currentItem.Bounds);

                //See the current item as the old item and wait for the next event
                _oldItemMouseOver = currentItem;
            }
        }

        protected override void OnMouseLeave(EventArgs argEventArgs)
        {
            base.OnMouseLeave(argEventArgs);

            if (DesignMode)
            {
                return;
            }

            if (_oldItemMouseOver != null)
            {
                _oldItemMouseOver.IsMouseOver = false;

                Invalidate(_oldItemMouseOver.Bounds);
                _itemPopupRectangle = Rectangle.Empty;
                //this.Invalidate(_itemPopupRectangle);
            }
        }

        //TODO: 023 - Enable FileInfo Popup
        //protected override void OnItemMouseHover(ListViewItemMouseHoverEventArgs argEventArgs)
        //{
        //    //Rectangle IconRectangle;
        //    //FileSystemListViewItem CurrentItem;
        //    //string PopupMessage;
        //    //Graphics CurrentGraphics;
        //    //SizeF StringSize;
        //    //Point PopupLocation;

        //    base.OnItemMouseHover(argEventArgs);

        //    //CurrentItem = (FileSystemListViewItem)argEventArgs.Item;

        //    //if (CurrentItem is FileListViewItem)
        //    //{
        //    //    PopupMessage = CurrentItem.ToolTip; // "Name:\r\nDate:\r\nSize:";
        //    //    CurrentGraphics = this.CreateGraphics();

        //    //    StringSize = CurrentGraphics.MeasureString(PopupMessage, CurrentItem.Font);
        //    //    //StringSize.Height = StringSize.Height + CurrentItem.SmallIcon.Height;

        //    //    PopupLocation = new Point(PointToClient(MousePosition).X + Cursor.Size.Width + 2, CurrentItem.argBounds.Bottom + 2);
        //    //    _itemPopupRectangle = new Rectangle(PopupLocation, StringSize.ToSize());

        //    //    //IconRectangle = new Rectangle(PopupLocation, CurrentItem.SmallIcon.Size);

        //    //    CurrentGraphics.FillRectangle(Brushes.Cornsilk, _itemPopupRectangle);
        //    //    CurrentGraphics.DrawRectangle(Pens.Black, _itemPopupRectangle);
        //    //    //CurrentGraphics.DrawIcon(CurrentItem.SmallIcon, IconRectangle);
        //    //    //PopupLocation.Offset(0, CurrentItem.SmallIcon.Height);

        //    //    CurrentGraphics.DrawString(PopupMessage, CurrentItem.Font, Brushes.Black, PopupLocation);
        //    //}
        //}

        //Cleanning up code stopped here
        protected override void OnItemActivate(EventArgs argEventArgs)
        {
            try
            {
                ListViewHitTestInfo clickedInfo = HitTest(PointToClient(MousePosition));
                FileSystemListViewItem clickedItem = (FileSystemListViewItem)clickedInfo.Item;


                if (clickedItem.Text == @"* Access Denied *")
                {
                    return;
                }

                // Determine if the item is a directory.
                if (!(clickedItem is FileListViewItem))
                {
                    SetPath(clickedItem.FullPath);
                }
                else
                {
                    try
                    {
                        Process.Start(clickedItem.FullPath);
                    }
                    catch (Exception)
                    {
                        MessageBox.Show(Resource1.No_File_Association, Resource1.File_Tracker_Title);
                    }
                }

                _selectedFileItems.Clear();
                _selectedDirectoryItems.Clear();
            }
            catch (Exception)
            {
                Focus();
            }
        }

        protected override void OnColumnClick(ColumnClickEventArgs argEventArgs)
        {
            // Determine whether the column is the same as the last column clicked.
            if (argEventArgs.Column != _sortColumn)
            {
                // Set the sort column to the new column.
                _sortColumn = argEventArgs.Column;
                // Set the sort order to ascending by default.
                Sorting = SortOrder.Ascending;
            }
            else
            {
                // Determine what the last sort order was and change it.
                if (Sorting == SortOrder.Ascending)
                {
                    Sorting = SortOrder.Descending;
                }
                else
                {
                    Sorting = SortOrder.Ascending;
                }
            }

            // Set the ListViewItemSorter property to a new ListViewItemComparer
            // object.
            ListViewItemSorter = new FileSystemListViewItemComparer(argEventArgs.Column, Sorting);

            Invalidate(true);

            base.OnColumnClick(argEventArgs);
        }

        //protected override void OnColumnWidthChanging(ColumnWidthChangingEventArgs argEventArgs)
        //{
        //    //Need to figure out why the column width changed
        //    //if(argEventArgs.NewWidth < maxWidth)
        //    //{
        //    // argEventArgs.NewWidth = maxWidth
        //    //}

        //    base.OnColumnWidthChanging(argEventArgs);
        //}

        #endregion

        #region ** RMB Menu Event Handlers **

        protected void OnRMBCopyHere(object sender, EventArgs argEventArgs)
        {
            if (_fileNames != null)
            {
                CopyItems(_fileNames);
            }
        }

        protected void OnRMBMoveHere(object sender, EventArgs argEventArgs)
        {
            if (_fileNames != null)
            {
                MoveItems(_fileNames);
            }
        }

        protected void OnRMBCancel(object sender, EventArgs argEventArgs)
        {
            //This is just here for people to have something to click on.
            return;
        }

        #endregion

        #region ** DirectoryWatcher events **

        //private void _directoryWatcher_CacheTimerElapsed(object sender, CacheTimerElapsedEventArgs argEventArgs)
        //{
        //    RefreshWorkDelegate ThreadRefresh = new RefreshWorkDelegate(RefreshWork);
        //    this.Invoke(ThreadRefresh, argEventArgs.FilenameList);
        //}

        //private delegate void RefreshWorkDelegate(List<string> FilenameList);

        //private void RefreshWork(List<string> FilenameList)
        //{

        //    //Might try Interlocked to maintain threading
        //    //0 indicates that the method is not in use.
        //    //if(0 == Interlocked.Exchange(ref usingResource, 1))

        //    FileSystemListViewItem CurrentItem;

        //    foreach (string CurrentFilename in FilenameList)
        //    {
        //        CurrentItem = this.Contains(CurrentFilename);
        //        if (CurrentItem != null)
        //        {

        //            //If item still is a file here
        //            if (File.Exists(CurrentFilename))
        //            {
        //                ////refresh Item
        //                CurrentItem.Refresh();
        //            }
        //            else
        //            {
        //                ////Remove Item
        //                Items.Remove(CurrentItem);
        //            }
        //        }
        //        else
        //        {
        //            if (File.Exists(CurrentFilename))
        //            {
        //                //Create new item
        //                CurrentItem = new FileSystemListViewItem(CurrentFilename);
        //                CurrentItem.FileSizeType = _sizeUnit;
        //                CurrentItem.SizePrecision = _sizePrecision;

        //                //Add Itme to list
        //                Items.Add(CurrentItem);
        //            }
        //            else
        //            {
        //            }
        //        }
        //    }

        //    this.Invalidate();
        //}

        #endregion

        #region ** Utility Methods **

        protected void CopyItems(List<string> ItemNames)
        {
            //TODO: 021 - Fix smaller files not removing extra content (What??)

            FileInfo CurrentFile;
            DirectoryInfo CurrentDirectory;
            Cursor = Cursors.WaitCursor;

            // loop through the string array, adding each filename to the ListBox
            foreach (string file in ItemNames)
            {
                CurrentFile = new FileInfo(file);
                if (CurrentFile.Exists)
                {
                    //Check if the destination file exists

                    //Copy
                    //Check for existing file and ask questions
                    CurrentFile.CopyTo(_currentPath + "\\" + CurrentFile.Name);

                    continue; //If it's a file skip checking the directory
                }

                CurrentDirectory = new DirectoryInfo(file);
                if (CurrentDirectory.Exists)
                {
                    //Copy
                    //Check for existing file and ask questions
                    CopyDir(CurrentDirectory, new DirectoryInfo(_currentPath), false);
                }
            }

            Cursor = Cursors.Default;
            CurrentFile = null;
            CurrentDirectory = null;
        }

        protected void MoveItems(List<string> ItemNames)
        {
            FileInfo CurrentFile;
            DirectoryInfo CurrentDirectory;
            Cursor = Cursors.WaitCursor;

            // loop through the string array, adding each filename to the ListBox
            foreach (string file in ItemNames)
            {
                CurrentFile = new FileInfo(file);
                if (CurrentFile.Exists)
                {
                    //Move
                    //Check for existing file and ask questions
                    //Check for ReadOnly sourcefile and ask questions
                    CurrentFile.MoveTo(_currentPath + "\\" + CurrentFile.Name);

                    continue; //If it's a file skip checking the directory
                }

                CurrentDirectory = new DirectoryInfo(file);
                if (CurrentDirectory.Exists)
                {
                    //Move
                    //Check for existing file and ask questions
                    //Check for ReadOnly sourcefile and ask questions
                    CurrentDirectory.MoveTo(_currentPath + "\\" + CurrentDirectory.Name);
                }
            }

            Cursor = Cursors.Default;
            CurrentFile = null;
            CurrentDirectory = null;
        }

        /// <summary>
        /// Opens the "Rename Item" form.
        /// </summary>
        public void RenameItems()
        {
            if (SelectedItems.Count <= 0)
            {
                MessageBox.Show("No items selected.");
                return;
            }

            //Pass Selected List into form and open rename form.
            using (FormRename renameForm = new FormRename())
            {
                renameForm.SelectedList.AddRange(SelectedItems); //.CopyTo(renameForm.SelectedList.ToArray(), 0);

                renameForm.ShowDialog(this);
            }

            //Refresh file list
            RefreshPath();
        }

        public void SetPath(string argFillPath)
        {
            Cursor = Cursors.WaitCursor;

            //try
            //{

            //Make sure the user didn't send us to nowheres-ville
            if (argFillPath == string.Empty)
            {
                ResumeLayout();
                return;
            }

            //THREAD: Check if the old request is still going
            if (_backgroundEngine.IsBusy)
            {
                //THREAD: Cancel the old thread.
                _backgroundEngine.CancelAsync();
            }

            //Just waiting for the background engine to stop
            while (_backgroundEngine.IsBusy) { }

            //Reset column sorting
            Sorting = SortOrder.Ascending;

            //Clear out the current list of items.
            //This is now thread safe
            Items.Clear();

            //Clear any selected files or directories
            //This is now thread safe
            _selectedFileItems.Clear();
            _selectedDirectoryItems.Clear();

            _currentPath = argFillPath;

            //Starts a new thread but not until it sets the AvailableFreeSpace
            _backgroundEngine.SetPath(argFillPath);
            _availableFreeSpace = _backgroundEngine.AvailableFreeSpace;

            Cursor = Cursors.Default;

            ResumeLayout();

            PathChanged.Raise(this, new FileSystemPathChangedEventArgs(argFillPath));

            Cursor = Cursors.Default;

        }

        protected void CopyDir(DirectoryInfo SourceDirectory, DirectoryInfo DestinationDirectory, bool ForceAction)
        {
            string DestinationFileName;
            FileInfo NewFile;

            try
            {
                //Get list of subdirs before adding new subdir 
                DirectoryInfo[] SubDirList = SourceDirectory.GetDirectories();

                //Create subdirectory
                DirectoryInfo DestSubDir = DestinationDirectory.CreateSubdirectory(SourceDirectory.Name);

                //Copy FileList from SourceDir to DestinationDir/SourceSub
                foreach (FileInfo CurrentFile in SourceDirectory.GetFiles())
                {
                    DestinationFileName = DestSubDir.FullName + "\\" + CurrentFile.Name;
                    NewFile = new FileInfo(DestinationFileName);
                    if (NewFile.Exists && !ForceAction)
                    {
                        throw new FileAlreadyExistsException(NewFile);
                    }

                    CurrentFile.CopyTo(DestinationFileName);
                }
                //Get list of SourceSubDirs
                foreach (DirectoryInfo SourceSubDir in SubDirList)
                {
                    //Loop through SourceSubdirs and call CopyDir for each
                    CopyDir(SourceSubDir, DestSubDir, ForceAction);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(@"Error in CopyDir" + ex.Message);
            }
            finally
            {
                NewFile = null;
            }
        }

        #endregion

        #region ** Event Listeners **

        private void _backgroundEngine_AddItemProgress(object sender, AddItemProgressEventArgs argEventArgs)
        {
            if (argEventArgs.ListItem != null)
            {
                Items.Add(argEventArgs.ListItem);
                FileListViewItem localFile = argEventArgs.ListItem as FileListViewItem;
                if (localFile == null) //If FileListViewItem doesn't work try DirectoryListViewItem
                {
                    DirectoryListViewItem localDir = argEventArgs.ListItem as DirectoryListViewItem;
                    if (localDir != null)
                    {
                        Directories.Add(localDir);
                    }
                }
                else
                {
                    Files.Add(localFile);
                }
                //OnAddItemProgress(argEventArgs);
                AddItemProgress.Raise(this, argEventArgs);
            }
        }

        void _backgroundEngine_AddItemComplete(object sender, AddItemCompleteEventArgs argEventArgs)
        {
            _availableFreeSpace = argEventArgs.AvailableFreeSpace;
        }

        #endregion

        #endregion
    }
}